home *** CD-ROM | disk | FTP | other *** search
/ The Very Best of Atari Inside / The Very Best of Atari Inside 1.iso / mint / mint110s / proc.c < prev    next >
C/C++ Source or Header  |  1994-02-11  |  15KB  |  673 lines

  1. /*
  2. Copyright 1990,1991,1992 Eric R. Smith.
  3. Copyright 1992,1993 Atari Corporation.
  4. All rights reserved.
  5. */
  6.  
  7. /* routines for handling processes */
  8.  
  9. #include "mint.h"
  10. #include "xbra.h"
  11.  
  12. static void do_wakeup_things P_((void));
  13.  
  14. extern short proc_clock;
  15.  
  16. /* global process variables */
  17. PROC *proclist;            /* list of all active processes */
  18. PROC *curproc;            /* current process        */
  19. PROC *rootproc;            /* pid 0 -- MiNT itself        */
  20. PROC *sys_q[NUM_QUEUES];
  21.  
  22. short time_slice = 2;        /* default; actual value comes from mint.cnf */
  23.  
  24. #if 0
  25. #define TIME_SLICE    2    /* number of 20ms ticks before process is
  26.                    pre-empted */
  27. #else
  28. #define TIME_SLICE time_slice
  29. #endif
  30.  
  31. /* macro for calculating number of missed time slices, based on a
  32.  * process' priority
  33.  */
  34. #define SLICES(pri)    (((pri) >= 0) ? 0 : -(pri))
  35.  
  36. extern FILESYS bios_filesys;
  37.  
  38. /*
  39.  * get a new process struct
  40.  */
  41.  
  42. PROC *
  43. new_proc()
  44. {
  45.     PROC *p;
  46.     void *pt;
  47.  
  48.     pt = kmalloc(page_table_size + 16);
  49.     if (!pt) return 0;
  50.  
  51.     p = (PROC *)kmalloc(SIZEOF(PROC));
  52.     if (!p) {
  53.         kfree(pt);
  54.         return 0;
  55.     }
  56. /* page tables must be on 16 byte boundaries, so we
  57.  * round off by 16 for that; however, we will want to
  58.  * kfree that memory at some point, so we squirrel
  59.  * away the original address for later use
  60.  */
  61.     p->page_table = ROUND16(pt);
  62.     p->pt_mem = pt;
  63.     return p;
  64. }
  65.  
  66. /*
  67.  * dispose of an old proc
  68.  */
  69.  
  70. void
  71. dispose_proc(p)
  72.     PROC *p;
  73. {
  74. TRACELOW(("dispose_proc"));
  75.     kfree(p->pt_mem);
  76.     kfree(p);
  77. }
  78.  
  79. /*
  80.  * create a new process that is (practically) a duplicate of the
  81.  * current one
  82.  */
  83.  
  84. PROC *
  85. fork_proc()
  86. {
  87.     PROC *p;
  88.     int i;
  89.     FILEPTR *f;
  90.     long_desc *pthold;
  91.     void *ptmemhold;
  92.  
  93.     if ((p = new_proc()) == 0) {
  94. nomem:
  95.         DEBUG(("fork_proc: insufficient memory"));
  96.         mint_errno = ENSMEM; return 0;
  97.     }
  98.  
  99. /* child shares most things with parent, but hold on to page table ptr */
  100.     pthold = p->page_table;
  101.     ptmemhold = p->pt_mem;
  102.     *p = *curproc;
  103.     p->page_table = pthold;
  104.     p->pt_mem = ptmemhold;
  105.  
  106. /* these things are not inherited */
  107.     p->ppid = curproc->pid;
  108.     p->pid = newpid();
  109.     p->sigpending = 0;
  110.     p->nsigs = 0;
  111.     p->sysstack = (long)(p->stack + STKSIZE - 12);
  112.     p->ctxt[CURRENT].ssp = p->sysstack;
  113.     p->ctxt[SYSCALL].ssp = (long)(p->stack + ISTKSIZE);
  114.     p->alarmtim = 0;
  115.     p->curpri = p->pri;
  116.     p->slices = SLICES(p->pri);
  117.     p->starttime = timestamp;
  118.     p->startdate = datestamp;
  119.  
  120.     ((long *)p->sysstack)[1] = FRAME_MAGIC;
  121.     ((long *)p->sysstack)[2] = 0;
  122.     ((long *)p->sysstack)[3] = 0;
  123.  
  124.     p->usrtime = p->systime = p->chldstime = p->chldutime = 0;
  125.  
  126. /* allocate space for memory regions: do it here so that we can fail
  127.  * before we duplicate anything else. The memory regions are
  128.  * actually copied later
  129.  */
  130.     p->mem = (MEMREGION **) kmalloc(p->num_reg * SIZEOF(MEMREGION *));
  131.     if (!p->mem) {
  132.         dispose_proc(p);
  133.         goto nomem;
  134.     }
  135.     p->addr = (virtaddr *)kmalloc(p->num_reg * SIZEOF(virtaddr));
  136.     if (!p->addr) {
  137.         kfree(p->mem);
  138.         dispose_proc(p);
  139.         goto nomem;
  140.     }
  141.  
  142. /* copy open handles */
  143.     for (i = MIN_HANDLE; i < MAX_OPEN; i++) {
  144.         if ((f = p->handle[i]) != 0) {
  145.             if (f->flags & O_NOINHERIT)
  146.         /* oops, we didn't really want to copy this handle */
  147.                 p->handle[i] = 0;
  148.             else
  149.                 f->links++;
  150.         }
  151.     }
  152.  
  153. /* copy root and current directories */
  154.     for (i = 0; i < NUM_DRIVES; i++) {
  155.         dup_cookie(&p->root[i], &curproc->root[i]);
  156.         dup_cookie(&p->curdir[i], &curproc->curdir[i]);
  157.     }
  158.  
  159. /* jr: copy ploadinfo */
  160.     strcpy (p->cmdlin, curproc->cmdlin);
  161.     strcpy (p->fname, curproc->fname);
  162.  
  163. /* clear directory search info */
  164.     zero((char *)p->srchdta, NUM_SEARCH * SIZEOF(DTABUF *));
  165.     zero((char *)p->srchdir, SIZEOF(p->srchdir));
  166.     p->searches = 0;
  167.  
  168. /* copy memory */
  169.     for (i = 0; i < curproc->num_reg; i++) {
  170.         p->mem[i] = curproc->mem[i];
  171.         if (p->mem[i] != 0)
  172.             p->mem[i]->links++;
  173.         p->addr[i] = curproc->addr[i];
  174.     }
  175.  
  176. /* now that memory ownership is copied, fill in page table */
  177.     init_page_table(p);
  178.  
  179. /* child isn't traced */
  180.     p->ptracer = 0;
  181.     p->ptraceflags = 0;
  182.  
  183.     p->starttime = Tgettime();
  184.     p->startdate = Tgetdate();
  185.  
  186.     p->q_next = 0;
  187.     p->wait_q = 0;
  188.     p->gl_next = proclist;
  189.     proclist = p;            /* hook into the process list */
  190.     return p;
  191. }
  192.  
  193. /*
  194.  * initialize the process table
  195.  */
  196.  
  197. void
  198. init_proc()
  199. {
  200.     int i;
  201.     FILESYS *fs;
  202.     fcookie dir;
  203.     long_desc *pthold;
  204.     void *ptmemhold;
  205.  
  206.     rootproc = curproc = new_proc();
  207.     assert(curproc);
  208.  
  209.     pthold = curproc->page_table;
  210.     ptmemhold = curproc->pt_mem;
  211.     zero((char *)curproc, (long)sizeof(PROC));
  212.     curproc->page_table = pthold;
  213.     curproc->pt_mem = ptmemhold;
  214.  
  215.     curproc->ppid = -1;        /* no parent */
  216.     curproc->domain = DOM_TOS;    /* TOS domain */
  217.     curproc->sysstack = (long) (curproc->stack+STKSIZE-12);
  218.     curproc->magic = CTXT_MAGIC;
  219.     curproc->memflags = F_PROT_S;    /* default prot mode: super-only */
  220.     ((long *)curproc->sysstack)[1] = FRAME_MAGIC;
  221.     ((long *)curproc->sysstack)[2] = 0;
  222.     ((long *)curproc->sysstack)[3] = 0;
  223.  
  224. /* NOTE: in main.c this could be changed, later */
  225.     curproc->base = _base;
  226.  
  227.     strcpy(curproc->name, "MiNT");
  228.  
  229. /* get some memory */
  230.     curproc->mem = (MEMREGION **)kmalloc(NUM_REGIONS*SIZEOF(MEMREGION *));
  231.     curproc->addr = (virtaddr *)kmalloc(NUM_REGIONS*SIZEOF(virtaddr));
  232.     assert(curproc->mem && curproc->addr);
  233.  
  234. /* make sure it's filled with zeros */
  235.     zero((char *)curproc->addr, NUM_REGIONS * SIZEOF(virtaddr));
  236.     zero((char *)curproc->mem, NUM_REGIONS * SIZEOF(MEMREGION *));
  237.     curproc->num_reg = NUM_REGIONS;
  238.  
  239. /* get root and current directories for all drives */
  240.     for (i = 0; i < NUM_DRIVES; i++) {
  241.         if ((fs = drives[i]) != 0 && (*fs->root)(i, &dir) == E_OK) {
  242.                 dup_cookie(&curproc->curdir[i], &dir);
  243.                 curproc->root[i] = dir;
  244.         } else {
  245.             curproc->root[i].fs = curproc->curdir[i].fs = 0;
  246.             curproc->root[i].dev = curproc->curdir[i].dev = i;
  247.         }
  248.     }
  249.  
  250.     init_page_table(curproc);
  251.  
  252. /* Set the correct drive. The current directory we
  253.  * set later, after all file systems have been loaded.
  254.  */
  255.  
  256.     curproc->curdrv = Dgetdrv();
  257.     proclist = curproc;
  258.  
  259.     curproc->umask = 0;
  260.  
  261. /*
  262.  * some more protection against job control; unless these signals are
  263.  * re-activated by a shell that knows about job control, they'll have
  264.  * no effect
  265.  */
  266.     curproc->sighandle[SIGTTIN] = curproc->sighandle[SIGTTOU] =
  267.         curproc->sighandle[SIGTSTP] = SIG_IGN;
  268.  
  269. /* set up some more per-process variables */
  270.     curproc->starttime = Tgettime();
  271.     curproc->startdate = Tgetdate();
  272.     if (has_bconmap)
  273.         curproc->bconmap = curbconmap;
  274.     else
  275.         curproc->bconmap = 1;
  276.  
  277.     curproc->logbase = (void *)Logbase();
  278.     curproc->criticerr = *((long ARGS_ON_STACK (**) P_((long)))0x404L);
  279. }
  280.  
  281. /*
  282.  * reset all process priorities to their base level
  283.  * called once per second, so that cpu hogs can get _some_ time
  284.  * slices :-).
  285.  */
  286.  
  287. void
  288. reset_priorities()
  289. {
  290.     PROC *p;
  291.  
  292.     for (p = proclist; p; p = p->gl_next) {
  293.         p->curpri = p->pri;
  294.         p->slices = SLICES(p->curpri);
  295.     }
  296. }
  297.  
  298. /*
  299.  * more priority code stuff:
  300.  * run_next(p, slices): schedule process "p" to run next, with "slices"
  301.  *       initial time slices; "p" does not actually start running until
  302.  *       the next context switch
  303.  * fresh_slices(slices): give the current process "slices" more slices in
  304.  *       which to run
  305.  */
  306.  
  307. void
  308. run_next(p, slices)
  309.     PROC *p;
  310.     int slices;    /* BUG: currently ignored */
  311. {
  312.     UNUSED(slices);
  313.  
  314.     p->slices = 0;
  315.     p->curpri = MAX_NICE;
  316.     p->wait_q = READY_Q;
  317.     p->q_next = sys_q[READY_Q];
  318.     sys_q[READY_Q] = p;
  319. }
  320.  
  321. void
  322. fresh_slices(slices)
  323.     int slices;
  324. {
  325.     curproc->slices = 0;
  326.     curproc->curpri = MAX_NICE+1;
  327.     proc_clock = slices;
  328. }
  329.  
  330. /*
  331.  * add a process to a wait (or ready) queue.
  332.  *
  333.  * processes go onto a queue in first in-first out order
  334.  */
  335.  
  336. void
  337. add_q(que, proc)
  338.     int que;
  339.     PROC *proc;
  340. {
  341.     PROC *q, **lastq;
  342.  
  343. /* "proc" should not already be on a list */
  344.     assert(proc->wait_q == 0);
  345.     assert(proc->q_next == 0);
  346.  
  347.     lastq = &sys_q[que];
  348.     q = *lastq;
  349.     while(q) {
  350.         lastq = &q->q_next;
  351.         q = *lastq;
  352.     }
  353.     *lastq = proc;
  354.     proc->wait_q = que;
  355.     if (que != READY_Q) {
  356.         proc->curpri = proc->pri;    /* reward the process */
  357.         proc->slices = SLICES(proc->curpri);
  358.     }
  359. }
  360.  
  361. /*
  362.  * remove a process from a queue
  363.  */
  364.  
  365. void
  366. rm_q(que, proc)
  367.     int que;
  368.     PROC *proc;
  369. {
  370.     PROC *q;
  371.     PROC *old = 0;
  372.  
  373.     assert(proc->wait_q == que);
  374.  
  375.     q = sys_q[que];
  376.     while (q && q != proc) {
  377.         old = q;
  378.         q = q->q_next;
  379.     }
  380.     if (q == 0)
  381.         FATAL("rm_q: unable to remove process from queue");
  382.  
  383.     if (old)
  384.         old->q_next = proc->q_next;
  385.     else
  386.         sys_q[que] = proc->q_next;
  387.  
  388.     proc->wait_q = 0;
  389.     proc->q_next = 0;
  390. }
  391.  
  392. /*
  393.  * preempt(): called by the vbl routine and/or the trap handlers when
  394.  * they detect that a process has exceeded its time slice and hasn't
  395.  * yielded gracefully. For now, it just does sleep(READY_Q); later,
  396.  * we might want to keep track of statistics or something.
  397.  */
  398.  
  399. void ARGS_ON_STACK
  400. preempt()
  401. {
  402.     extern short bconbsiz;    /* in bios.c */
  403.  
  404.     if (bconbsiz)
  405.         (void)bflush();
  406.     else {
  407.         /* punish the pre-empted process */
  408.         if (curproc->curpri >= MIN_NICE)
  409.             curproc->curpri -= 1;
  410.     }
  411.     sleep(READY_Q, curproc->wait_cond);
  412. }
  413.  
  414. /*
  415.  * sleep(que, cond): put the current process on the given queue, then switch
  416.  * contexts. Before a new process runs, give it a fresh time slice. "cond"
  417.  * is the condition for which the process is waiting, and is placed in
  418.  * curproc->wait_cond
  419.  */
  420.  
  421. static void
  422. do_wakeup_things()
  423. {
  424. /*
  425.  * check for stack underflow, just in case
  426.  */
  427.     auto int foo;
  428.     PROC *p;
  429.  
  430.     p = curproc;
  431.  
  432.     if ( p->pid != 0 &&
  433.          ((long)&foo) < (long)p->stack + ISTKSIZE + 512 ) {
  434.         ALERT("stack underflow");
  435.         handle_sig(SIGBUS);
  436.     }
  437.  
  438. /* see if process' time limit has been exceeded */
  439.  
  440.     if (p->maxcpu) {
  441.         if (p->maxcpu <= p->systime + p->usrtime) {
  442.             DEBUG(("cpu limit exceeded"));
  443.             raise(SIGXCPU);
  444.         }
  445.     }
  446.  
  447. /*
  448.  * check for alarms and similar time out stuff (see timeout.c)
  449.  */
  450.  
  451.     checkalarms();
  452.     if (p->sigpending)
  453.         check_sigs();        /* check for signals */
  454.  
  455.     proc_clock = TIME_SLICE;    /* get a fresh time slice */
  456.     p->slices = SLICES(p->curpri);
  457. }
  458.  
  459. /*
  460.  * sleep: returns 1 if no signals have happened since our last sleep, 0
  461.  * if some have
  462.  */
  463.  
  464. int ARGS_ON_STACK 
  465. sleep(que, cond)
  466.     int que;
  467.     long cond;
  468. {
  469.     PROC *p;
  470.     short sr;
  471.     ulong onsigs = curproc->nsigs;
  472.     extern short kintr;    /* in bios.c */
  473. #ifndef MULTITOS
  474. #ifdef FASTTEXT
  475.     extern int hardscroll;    /* in fasttext.c */
  476. #endif
  477. #endif
  478.  
  479. /*
  480.  * if there have been keyboard interrupts since our last sleep, check for
  481.  * special keys like CTRL-ALT-Fx
  482.  */
  483.  
  484.     if (kintr) {
  485.         (void)checkkeys();
  486.         kintr = 0;
  487.     }
  488.  
  489.     if (que == READY_Q && !sys_q[READY_Q]) {
  490. /* we're just going to wake up again right away! */
  491.         do_wakeup_things();
  492.         return (onsigs != curproc->nsigs);
  493.     }
  494.  
  495.     sr = spl7();
  496.  
  497.     add_q(que, curproc);
  498.     curproc->wait_cond = cond;
  499.  
  500.     if (!sys_q[READY_Q]) {
  501. /* hmm, no-one is ready to run. might be a deadlock, might not.
  502.  * first, try waking up any napping processes; if that doesn't work,
  503.  * run the root process, just so we have someone to charge time
  504.  * to.
  505.  */
  506.         wake(SELECT_Q, (long)nap);
  507.         if (!sys_q[READY_Q]) {
  508.             p = rootproc;        /* pid 0 */
  509.             rm_q(p->wait_q, p);
  510.             add_q(READY_Q, p);
  511.         }
  512.     }
  513.  
  514. /*
  515.  * Walk through the ready list, to find what process should run next.
  516.  * Lower priority processes don't get to run every time through this
  517.  * loop; if "p->slices" is positive, it's the number of times that they
  518.  * will have to miss a turn before getting to run again
  519.  */
  520.  
  521. /*
  522.  * Loop structure:
  523.  *    while (we haven't picked anybody) {
  524.  *        for (each process) {
  525.  *            if (sleeping off a penalty) {
  526.  *                decrement penalty counter
  527.  *            }
  528.  *            else {
  529.  *                pick this one and break out of both loops
  530.  *            }
  531.  *        }
  532.  *    }
  533.  */
  534.     p = 0;
  535.  
  536.     while (!p) {
  537.         for (p = sys_q[READY_Q]; p; p = p->q_next) {
  538.             if (p->slices > 0)
  539.                 p->slices--;
  540.             else
  541.                 break;
  542.         }
  543.     }
  544.  
  545.     /* p is our victim */
  546.  
  547.     rm_q(READY_Q, p);
  548.  
  549.     spl(sr);
  550.  
  551.     if (save_context(&(curproc->ctxt[CURRENT]))) {
  552. /*
  553.  * restore per-process variables here
  554.  */
  555. #ifndef MULTITOS
  556. #ifdef FASTTEXT
  557.         if (!hardscroll)
  558. #endif
  559.             *((void **)0x44eL) = curproc->logbase;
  560. #endif
  561.         do_wakeup_things();
  562.         return (onsigs != curproc->nsigs);
  563.     }
  564. /*
  565.  * save per-process variables here
  566.  */
  567. #ifndef MULTITOS
  568. #ifdef FASTTEXT
  569.     if (!hardscroll)
  570. #endif
  571.         curproc->logbase = *((void **)0x44eL);
  572. #endif
  573.     curproc->ctxt[CURRENT].regs[0] = 1;
  574.     curproc = p;
  575.     proc_clock = TIME_SLICE;    /* fresh time */
  576.     if ((p->ctxt[CURRENT].sr & 0x2000) == 0) {    /* user mode? */
  577.         leave_kernel();
  578.     }
  579.     assert(p->magic == CTXT_MAGIC);
  580.     change_context(&(p->ctxt[CURRENT]));
  581.     /* not reached */
  582.     return 0;
  583. }
  584.  
  585. /*
  586.  * wake(que, cond): wake up all processes on the given queue that are waiting
  587.  * for the indicated condition
  588.  */
  589.  
  590. void ARGS_ON_STACK 
  591. wake(que, cond)
  592.     int que;
  593.     long cond;
  594. {
  595.     PROC *p;
  596.  
  597.     if (que == READY_Q) {
  598.         ALERT("wake: why wake up ready processes??");
  599.         return;
  600.     }
  601. top:
  602.     for(p = sys_q[que]; p; p = p->q_next) {
  603.         if (p->wait_cond == cond) {
  604.             short s = spl7();
  605.             rm_q(que, p);
  606.             add_q(READY_Q, p);
  607.             spl(s);
  608.             goto top;
  609.         }
  610.     }
  611. }
  612.  
  613. /*
  614.  * wakeselect(p): wake process p from a select() system call
  615.  * may be called by an interrupt handler or whatever
  616.  */
  617.  
  618. void ARGS_ON_STACK 
  619. wakeselect(param)
  620.     long param;
  621. {
  622.     PROC *p = (PROC *)param;
  623.     short s;
  624.  
  625.     s = spl7();    /* block interrupts */
  626.     if(p->wait_cond == (long)wakeselect) {
  627.         p->wait_cond = 0;
  628.     }
  629.     if (p->wait_q == SELECT_Q) {
  630.         rm_q(SELECT_Q, p);
  631.         add_q(READY_Q, p);
  632.     }
  633.     spl(s);
  634. }
  635.  
  636. /*
  637.  * dump out information about processes
  638.  */
  639.  
  640. /*
  641.  * kludge alert! In order to get the right pid printed by FORCE, we use
  642.  * curproc as the loop variable.
  643.  *
  644.  * I have changed this function so it is more useful to a user, less to
  645.  * somebody debugging MiNT.  I haven't had any stack problems in MiNT
  646.  * at all, so I consider all that stack info wasted space.  -- AKP
  647.  */
  648.  
  649. #ifdef DEBUG_INFO
  650. static const char *qstring[] = {
  651.     "run", "ready", "wait", "iowait", "zombie", "tsr", "stop", "select"
  652. };
  653.  
  654. /* UNSAFE macro for qname, evaluates x 1, 2, or 3 times */
  655. #define qname(x) ((x >= 0 && x < NUM_QUEUES) ? qstring[x] : "unkn")
  656. #endif
  657.  
  658. void
  659. DUMPPROC()
  660. {
  661. #ifdef DEBUG_INFO
  662.     PROC *p = curproc;
  663.  
  664.     for (curproc = proclist; curproc; curproc = curproc->gl_next) {
  665.         FORCE("state %s PC: %lx BP: %lx",
  666.         qname(curproc->wait_q),
  667.         curproc->ctxt[SYSCALL].pc,
  668.         curproc->base);
  669.     }
  670.     curproc = p;        /* restore the real curproc */
  671. #endif
  672. }
  673.